package main

import (
	"bufio"
	"crypto/md5"
	"encoding/hex"
	"fmt"
	"goIp/config"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"regexp"
	"strings"
	"time"

	"github.com/gin-gonic/gin"
)

var confSrc = "./1.conf"

type ParamsInfo struct {
	User string `json:"user" form:"user" uri:"user" binding:"required"`
	Sign string `json:"sign" form:"sign" uri:"sign" binding:"required"`
	Type uint   `json:"type" form:"type" uri:"type" default:"0"`
}

// 获取到md5
func GetMd5(data string) string {

	// 创建一个新的MD5 hash实例
	hash := md5.New()

	// 将字符串写入hash
	hash.Write([]byte(data))

	// 计算MD5签名并转换为十六进制字符串
	return hex.EncodeToString(hash.Sum(nil))
}

// 获取签名信息
func GetSign(userInfo config.UserInfo) string {
	now := time.Now()
	dateStr := now.Format("20060102")
	hour := now.Hour()
	min := now.Minute()
	signStr := fmt.Sprintf("u=%s&t=%s&h=%d&m=%d&p=%s&u=%s", userInfo.User, dateStr,hour,min, userInfo.Pass, userInfo.User)
	fmt.Println("签名字符串signStr:",signStr)
	sign := GetMd5(signStr)
	return sign
}

func main() {
	C := config.GetConfig()

	// 创建记录日志的文件
	f, _ := os.Create("gin.log")
	gin.DefaultWriter = io.MultiWriter(f)

	// 创建一个默认的Gin路由器
	router := gin.Default()

	// 声明一个GET请求路径
	router.GET("/uIp", func(c *gin.Context) {
		var params ParamsInfo
		if err := c.ShouldBindQuery(&params); err != nil {
			c.JSON(400, gin.H{
				"message": "1",
			})
			return
		}
		if params.User == "" || params.Sign == "" {
			c.JSON(400, gin.H{
				"message": "2",
			})
			return
		}

		var userFlag bool
		var userInfo config.UserInfo
		userFlag = false
		for _, v := range config.C.Users {
			if v.User == params.User {
				userInfo = v
				userFlag = true
				fmt.Println(v.User)
			}
		}

		if !userFlag {
			c.JSON(400, gin.H{
				"message": "no u",
			})
			return
		}

		// 获取签名
		sign := GetSign(userInfo)
		fmt.Println("sign:", sign, params.Sign)
		fmt.Println("user:", userInfo.User, params.User)
		if params.User != userInfo.User || params.Sign != sign {
			c.JSON(400, gin.H{
				"message": "no sign",
			})
			return
		}

		// 读取文件
		data, err := ioutil.ReadFile(C.Src)
		if err != nil {
			c.JSON(400, gin.H{
				"message": "1",
			})
			panic(err)
			return
		}

		clientIP := c.ClientIP()

		fmt.Println(params.Type)

		// 定义正则表达式和替换内容
		replacement := fmt.Sprintf(`##START##
		allow %s;#公司ip
		##END##`, clientIP)
		if params.Type == 1 {
			replacement = fmt.Sprintf(`##START##
		$1
		allow %s;#临时ip
		##END##`, clientIP)
		}
		re := regexp.MustCompile(`(?s)##START##(.*?)##END##`)

		// 执行正则替换
		newData := re.ReplaceAll(data, []byte(replacement))

		// 写入新文件
		err = ioutil.WriteFile(C.Src, newData, 0644)
		if err != nil {
			c.JSON(400, gin.H{
				"message": "1",
			})
			panic(err)
		}

		fmt.Println("写入成功,操作nginx")
		RoleadNginx()

		LogStr(fmt.Sprintf("user:%s,ip:%s,type:%d,date:%s\n", userInfo.User, clientIP, params.Type, time.Now().Format("2006-01-02 15:04:05")))

		c.JSON(200, gin.H{
			"message":  "成功",
			"account":  userInfo.User, // 用户名
			"clientIP": clientIP,
		})
	})

	server := ":" + fmt.Sprintf("%d", C.Port)
	fmt.Println("端口：", server)
	fmt.Println("配置路径：", C.Src)

	// 启动服务器，监听8080端口
	router.Run(server)
}

// RoleadNginx 重新载入配置 nginx
func RoleadNginx() {
	fmt.Println("nginx reload")
	// 要执行的命令 nginx -s reload
	cmd := "sudo systemctl reload nginx"

	// 将命令字符串分割成一个字符串数组
	args := strings.Split(cmd, " ")

	// 创建一个*Cmd结构体实例
	execCmd := exec.Command(args[0], args[1:]...)

	// 运行命令并获取输出
	output, err := execCmd.Output()

	// 检查是否有错误
	if err != nil {
		fmt.Printf("Error executing command: %s\n", err)
		return
	}

	// 打印命令输出
	fmt.Printf("Command output:\n%s\n", string(output))
}

// 记录
func LogStr(dataToWrite string) {
	// 打开文件
	file, err := os.OpenFile("./success.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
	if err != nil {
		fmt.Printf("Error opening file: %v\n", err)
		return
	}
	defer file.Close()

	// 将数据写入文件
	// 创建一个bufio.Writer
	writer := bufio.NewWriter(file)

	// 写入内容
	_, err = writer.WriteString(dataToWrite)
	if err != nil {
		fmt.Println("Error writing to file:", err)
		return
	}

	// 确保所有缓冲的写入操作都已执行
	err = writer.Flush()
	if err != nil {
		fmt.Println("Error flushing writer:", err)
		return
	}

	fmt.Println("write file successfully.", dataToWrite)
}
